package com.yulian.yulianbackend.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yulian.yulianbackend.common.BaseResponse;
import com.yulian.yulianbackend.common.ErrorCode;
import com.yulian.yulianbackend.common.ResultUtils;
import com.yulian.yulianbackend.exception.BusinessException;
import com.yulian.yulianbackend.model.domain.User;
import com.yulian.yulianbackend.model.domain.request.UserLoginRequest;
import com.yulian.yulianbackend.model.domain.request.UserRegisterRequest;
import com.yulian.yulianbackend.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

import static com.yulian.yulianbackend.contant.UserConstant.USER_LOGIN_STATE;

/**
 * 用户 接口 / 控制器
 *
 * @author yulian174
 * @version 1.0
 */
@RestController//适用于编写restful风格的api，响应(返回)的数据类型都是JSON格式
@RequestMapping("/user") //请求的路径
//允许跨域的域名和允许跨域的请求方法
// 允许后端接受该 URL 地址的请求
//@CrossOrigin(originPatterns = "*", allowCredentials = "true")
@CrossOrigin(origins = {"http://localhost:5173/"})
@Slf4j
public class UserController {

    //调用业务逻辑
    @Resource   //Spoot里提供的注解
    private UserService userService;    //将userService引用到类里面

    //用户注册(返回用户id，long)
    @PostMapping("/register")//Post请求,接口地址为register
    public BaseResponse<Long> userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
        //@RequestBody：让SpootMVC框架把前端传来的JSON参数和该对象做一个关联(userRegisterRequest)
        if (userRegisterRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //调用业务逻辑的用户注册
        String userAccount = userRegisterRequest.getUserAccount();
        String userPassword = userRegisterRequest.getUserPassword();
        String checkPassword = userRegisterRequest.getCheckPassword();
//        String planeCode = userRegisterRequest.getPlaneCode();
        //如果以上的任何一个参数为空，就不进入到业务逻辑层
        if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword)) {
            return null;
        }
        long result = userService.userRegister(userAccount, userPassword, checkPassword);
        return ResultUtils.success(result);
    }

    //用户登录(返回脱敏后的用户对象)
    @PostMapping("/login")//Post请求,接口地址为login
    //相对于在user对象外再套一层BaseResponse
    public BaseResponse<User> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
        //@RequestBody：让SpootMVC框架把前端传来的JSON参数和该对象做一个关联(userRegisterRequest)
        //Get请求不需要@RequestBody
        if (userLoginRequest == null) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR);
        }
        //调用业务逻辑的用户登录
        String userAccount = userLoginRequest.getUserAccount();
        String userPassword = userLoginRequest.getUserPassword();
        //如果以上的任何一个参数为空，就不进入到业务逻辑层
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR);
        }
        User user = userService.userLogin(userAccount, userPassword, request);
        return ResultUtils.success(user);
    }

    //用户注销
    @PostMapping("/logout")//Post请求,接口地址为logout
    public BaseResponse<Integer> userLogout(HttpServletRequest request) {
        if (request == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        int result = userService.userLogout(request);
        return ResultUtils.success(result);
    }

    //获取当前登录用户信息接口
    //从请求中拿到用户cookie信息
    @GetMapping("/current")
    public BaseResponse<User> getCurrentUser(HttpServletRequest request) {

        //从请求中获取用户的登录态
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User currentUser = (User) userObj;
        if (currentUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        long userId = currentUser.getId();
        // todo 校验用户是否合法 (todo: 待办事项)
        //从数据库中查询userId对应的数据库信息
        User user = userService.getById(userId);
        //返回脱敏后的user
        User safetyUser = userService.getSafetyUser(user);
        return ResultUtils.success(safetyUser);
    }

    //查询用户(允许根据用户名查询)接口
    @GetMapping("/search")
    public BaseResponse<List<User>> searchUsers(String username, HttpServletRequest request) {
        //仅管理员可查询
        if (!userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //判断不为空并且不为空格, 如果不为空的话执行···
        if (StringUtils.isNotBlank(username)) {
            //允许包含，要查询的值就是传入的形参username(右边)
            queryWrapper.like("username", username);
        }
        List<User> userList = userService.list(queryWrapper);
        //java8知识
        //将userList转换成数据流，
        //然后遍历其中的每一个元素
        //将它的每个密码设置为空
        //再重新拼成一个完整的list，最后返回的还是list
        List<User> listuser = userList.stream().map(user -> userService.getSafetyUser(user)).collect(Collectors.toList());
        return ResultUtils.success(listuser);
    }

    //编写Get接口
    //该接口从数据库中查询标签并返回给前端搜索结果页面
    @GetMapping("/search/tags")
    //返回值依然是用户列表
    //接受前端传来的tags列表
    //@RequestParam(required = false)用于指示该请求参数是非必需的。
    public BaseResponse<List<User>> searchUsersByTags(@RequestParam(required = false) List<String> tagNameList) {
        //建议在控制层先校验一次非空比较好，searchUsersByTags未必是别人提供的
        //如果为空的话
        if (CollectionUtils.isEmpty(tagNameList)) {
            // 自定义异常
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        List<User> userList = userService.searchUsersByTags(tagNameList);
        return ResultUtils.success(userList);
    }

    //删除用户接口
    @PostMapping("/delete")
    //前端传入id
    public BaseResponse<Boolean> deleteUser(@RequestBody long id, HttpServletRequest request) {
        if (userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH);
        }
        //id不能为空
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        boolean b = userService.removeById(id);//逻辑删除
        return ResultUtils.success(b);
    }


    // Post 请求， 表示接口 URL 地址 /user/update
    // 表示用户是否修改信息成功
    @PostMapping("/update")
    // 返回值值 ( 大于1表示修改成功 )
    // 如果有一些不希望用户修改的内容，可以封装一个 UserDTO
    // 泛型只能返回 封装类
    // 添加参数 request ( 需要知道当前登录的用户信息 )
    // 根据前端请求的 请求头 中提取 cookie ( 包含用户信息 )
    // 根据该 cookie 从后台的会话 Session 中 获取到当前已经登录的用户信息
    // 请求的是JSON数据，用注解@RequestBody
    public BaseResponse<Integer> updateUser(@RequestBody User user, HttpServletRequest request) {
        // 1. 校验参数是否为空
        if (user == null) {
            // 如果为空，就抛出用户自定义的异常 ( 用来表示前端没有传入任何参数 )
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 在外层也获取一下用户信息
        User loginUser = userService.getLoginUser(request);
        // 2. 校验权限 （ 判断修改用户信息的是否是 本人 / 管理员 ）
        // 3. 触发更新
        // 调用 更新用户信息的方法 , 返回值是 int，将登录的用户信息作为参数传递给 updateUser
        int result = userService.updateUser(user, loginUser);
        // 返回一个自己成功封装的 成功反应类
        return ResultUtils.success(result);
    }

    // 编写一个封装类， 获取当前登录用户
//    private User getLoginUser(HttpServletRequest request) {}
}
